package cn.jtfadmin.base.shiro.support;

import cn.jtfadmin.base.lang.common.security.UserDetails;
import cn.jtfadmin.base.lang.config.user.UserRealHolder;
import cn.jtfadmin.base.shiro.config.UserBuilder;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.apache.shiro.subject.support.DelegatingSubject;
import org.apache.shiro.util.ThreadContext;
import org.apache.shiro.web.subject.support.WebDelegatingSubject;

import java.util.List;
import java.util.Objects;

public  class ShiroUserHoler implements UserRealHolder {

    private List<UserBuilder> userBuilders;

    public List<UserBuilder> getUserBuilders() {
        return userBuilders;
    }

    public void setUserBuilders(List<UserBuilder> userBuilders) {
        this.userBuilders = userBuilders;
    }

    public ShiroUserHoler(List<UserBuilder> userBuilders) {
        this.userBuilders = userBuilders;
    }

    @Override
    public UserDetails getUserDetails() {
        try{
            // securityManager 未发现
            Object principal = SecurityUtils.getSubject().getPrincipal();
            return (UserDetails) principal;
        }catch (Exception e){
            return null;
        }
    }

    @Override
    public String getToken() {
        Session session = SecurityUtils.getSubject().getSession(false);
        if(session == null){
            return null;
        }
        return session.getId().toString();
    }

    @Override
    public UserDetails refreshCurrentUser() {
        UserDetails userDetails = getUserDetails();
        if(Objects.nonNull(userDetails)){
            String type = userDetails.getType();
            String userId = userDetails.getUserId();
            Session session = SecurityUtils.getSubject().getSession(false);
            if(Objects.nonNull(session)){
                Subject subject = SecurityUtils.getSubject();
                PrincipalCollection principals = subject.getPrincipals();
                ThreadContext.unbindSubject();
                UserDetails details = builderUserDetails(userId, type);
                PrincipalCollection principalCollection = PrincipalUtils.createPrincipalCollection(details, principals.getRealmNames().iterator().next());
                subject = copySubject(subject, principalCollection);
                session.setAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY, principalCollection);
                ThreadContext.bind(subject);
                return userDetails;
            }
        }
        return null;
    }


    @Override
    public  UserDetails builderUserDetails(String userId, String userType) {
        return PrincipalUtils.buildUserDetails( userId,userType);
    }

    private  Subject copySubject(Subject subject,PrincipalCollection principalCollection ){
        if(subject instanceof WebDelegatingSubject){
            WebDelegatingSubject delegatingSubject = new WebDelegatingSubject(
                    principalCollection, subject.isAuthenticated(),
                    ((WebDelegatingSubject) subject).getHost(),
                    subject.getSession(false),
                    ((WebDelegatingSubject) subject).getServletRequest(),
                    ((WebDelegatingSubject) subject).getServletResponse(),
                    ((WebDelegatingSubject) subject).getSecurityManager()
            );
            subject = delegatingSubject;
        } else
        if(subject instanceof DelegatingSubject){
            DelegatingSubject delegatingSubject = new DelegatingSubject(
                    principalCollection, subject.isAuthenticated(),
                    ((DelegatingSubject) subject).getHost(),
                    subject.getSession(false),
                    true,
                    ((DelegatingSubject) subject).getSecurityManager()
            );
            subject = delegatingSubject;
        }
        return subject;
    }

}
